package org.luosl.webmagicx.handler

import java.io.{File, IOException}
import java.util.concurrent.atomic.AtomicInteger

import org.apache.commons.codec.digest.DigestUtils
import org.apache.commons.io.{FileUtils, FilenameUtils}
import org.luosl.webmagicx.conf.{ConfException, Props, SpiderConf}
import us.codecraft.webmagic.{ResultItems, Task}
import org.luosl.webmagicx.conf.MatcherConverters._
import org.luosl.webmagicx.conf.PropType._

import scalaj.http.{Http, HttpResponse}

class DownloadHandler(sc:SpiderConf, props:Props) extends BaseHandler (sc, props){

  val needProcessCell:List[Props] = props.props("*")

  override def process(items: ResultItems, task: Task): Unit = {
    needProcessCell.foreach{ prop=>
      val src:String = prop.value("src")(strType)
      val target:String = prop.value("target")(strType)
      val saveDir:String = prop.value("saveDir")(strType)
      val returnValue = prop.valueOrDefault("returnValue")(strType)("fileName")
      val retryTimes:Int = prop.valueOrDefault("retryTimes")(intType)(0)
      val needDownloadUrl:String = items.get(src)
      val byteArr:Array[Byte] = download(needDownloadUrl,retryTimes)
      logInfo(s"文件[url=$needDownloadUrl]下载成功!!")
      val result:String = returnValue match {
        case "md5" =>
          val md5:String = DigestUtils.md5Hex(byteArr)
          save(byteArr, s"$saveDir${File.separator}$md5")
          md5
        case str:String if str == "path" || str == "fileName" =>
          val fileName:String = FilenameUtils.getName(needDownloadUrl)
          val savePath:String = s"$saveDir${File.separator}$fileName"
          save(byteArr,savePath)
          if(str == "path") savePath else fileName
        case str:String =>
          throw ConfException(s"DownloadHandler download 的 returnValue 属性不支持:$str")
      }
      items.put(target, result)
    }
  }

  /**
    * 下载
    * @param url url
    * @param retryTimes retryTimes
    * @return
    */
  def download(url:String,retryTimes:Int):Array[Byte] = {
    def download(url:String):Array[Byte] = Http(url).asBytes.body
    val rt:AtomicInteger = new AtomicInteger(retryTimes)
    try{
      download(url)
    }catch {
      case e:IOException =>
        val nowTimes:Int = retryTimes - rt.get()
        if(rt.getAndDecrement() > 0){
          logInfo(s"正在进行第:$nowTimes 词尝试...")
          download(url)
        }else{
          throw new RuntimeException(s"无法下载:url=$url", e)
        }
    }
  }

  /**
    * 曹村文件
    * @param byteArr byteArr
    * @param path path
    */
  def save(byteArr:Array[Byte],path:String): Unit ={
    val file:File = new File(path)
    val parent:File = file.getParentFile
    if(parent.exists() && parent.isFile)
      throw new RuntimeException(s"${parent.getAbsolutePath}不是一个目录")
    if(!parent.exists())
      FileUtils.forceMkdir(parent)
    FileUtils.writeByteArrayToFile(file,byteArr)
  }
}
